﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CFE
{
	public class ClosureProxy
	{
		private Process process;
		private Project.WorkItem workItem;

		private string BuildRelativePath(string basePath, string targetPath)
		{
			int index = basePath.LastIndexOf('/');

			if (index == -1)
				return targetPath;

			basePath = basePath.Substring(0, index+1);

			targetPath = targetPath.Replace(basePath, "");
			return targetPath;

		}

		private ProcessStartInfo CreateProcessStartInfo(Project.WorkItem item)
		{
			workItem = item;
			string compilerPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "compiler.jar");

			List<string> args = new List<string>();
			args.Add("-jar");
			args.Add("\"" + compilerPath + "\"");
			

			args.Add("\"--js_output_file=" + Path.GetFileName( item.OutputFilename.Replace('/', '\\')) + "\"");
			if (!string.IsNullOrEmpty(item.SourceMapFilename))
				args.Add("\"--create_source_map=" + item.SourceMapFilename + "\"");

			foreach (string input in item.InputFilenames)
			{
				args.Add("\"--js=" + input + "\"");
			}

			string commandLine = String.Join(" ", args.ToArray());

			ProcessStartInfo psi = new ProcessStartInfo("java", commandLine);
			psi.UseShellExecute = false;
			psi.WorkingDirectory = Path.Combine(Path.GetDirectoryName(item.Project.ProjectFilename), Path.GetDirectoryName(item.OutputFilename.Replace('/', '\\')));

			psi.RedirectStandardOutput = true;
			psi.RedirectStandardError = true;

			return psi;
		}
		public ClosureProxy(Project.WorkItem workItem)
		{
			ProcessStartInfo psi = CreateProcessStartInfo(workItem);
			process = new Process();
			process.StartInfo = psi;
			process.EnableRaisingEvents = true;

			process.Exited += CompilationCompleteCallback;

		}

		private void CompilationCompleteCallback(object sender, EventArgs e)
		{
			if (process.ExitCode == 0)
			{
				if (!string.IsNullOrEmpty(workItem.SourceMapFilename))
				{
					string outputPath = Path.Combine(Path.GetDirectoryName(workItem.Project.ProjectFilename), workItem.OutputFilename);
					string sourceMapPath = Path.Combine(Path.GetDirectoryName(workItem.Project.ProjectFilename),  Path.GetDirectoryName(workItem.OutputFilename), workItem.SourceMapFilename);
					string modified = null;
					using (StreamReader sr = new StreamReader(sourceMapPath))
					{
						string original = sr.ReadToEnd();
						modified = original.Replace("\\", "/");
					}
					using (StreamWriter sw = new StreamWriter(sourceMapPath))
					{
						sw.WriteLine(modified);
					}
					using (var sw = new StreamWriter(outputPath, true))
					{
						sw.WriteLine();
						sw.WriteLine("//@ sourceMappingURL={0}", BuildRelativePath(workItem.OutputFilename, workItem.SourceMapFilename));
					}

				}
			}

			if (this.CompilationComplete != null)
			{
				CompilationCompleteEventArgs args = new CompilationCompleteEventArgs();
				args.Success = process.ExitCode == 0;
				args.Output = process.StandardError.ReadToEnd();
				args.WorkItem = workItem;
				
				CompilationComplete(this, args);
			}
			
		}
		public bool Start()
		{
			
			Debug.WriteLine("cd " + process.StartInfo.WorkingDirectory);
			Debug.WriteLine(process.StartInfo.FileName + " " + process.StartInfo.Arguments);

			return process.Start();
		}
		public bool Stop()
		{
			if (process.HasExited)
				return false;
			process.Kill();
			return true;
		}

		public int Wait()
		{
			process.WaitForExit();

			Console.WriteLine(process.StandardOutput.ReadToEnd());

			return process.ExitCode;
		}

		public class CompilationCompleteEventArgs : EventArgs
		{
			public bool Success { get; set; }
			public string Output { get; set; }
			public Project.WorkItem WorkItem { get; set; }
		}

		public event EventHandler<CompilationCompleteEventArgs> CompilationComplete;
	}
}
